﻿#include "stdafx.h"
#include "sbcs.h"
#if _SB_PTHREAD_
#include <pthread.h>
#endif
#ifdef _MSC_VER
#include <intrin.h>
#endif

//////////////////////////////////////////////////////////////////////////
// spin lock
#if defined(__GNUC__) && _SB_ARM_
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7S__)
# define K_ARM_BARRIER "dmb"
#else // arch6
# define K_ARM_BARRIER "mcr p15, 0, r0, c7, c10, 5"
#endif

kcham k_lock_try(kLock* self)
{
	int m;

	// [2013-12-10 ksh]
	// 일단... ldrex는 요즘 ARM 모바일에서는 다 지원하는 듯함.
	__asm__ __volatile__(
		"ldrex %0, [%2]; \n"
		"cmp %0, %1; \n"
		"strexne %0, %1, [%2]; \n"
K_ARM_BARRIER : "=&r"( r ) : "r"( 1 ), "r"( &v_ ) : "memory", "cc");

	return r == 0;
}

void k_lock_enter(kLock* self)
{
	kint i;
	for (i=0; !k_lock_try(self); i++)
		k_yield(i);
}

void k_lock_leave(kLock* self)
{
	__asm__ __volatile__(K_ARM_BARRIER ::: "memory");
	*self = 0;
}
#elif _SB_PTHREAD_ && !defined(__GNUC__)
kcham k_lock_try(kLock* self)
{
	return pthread_mutex_trylock(self)==0;
}

void k_lock_enter(kLock* self)
{
	pthread_mutex_lock(self);
}

void k_lock_leave(kLock* self)
{
	pthread_mutex_unlock(self);
}
#else
kcham k_lock_try(kLock* self)
{
	volatile long m = k_atomexch(self, 1);
	KSAFE_BARRIER;
	return m == 0;
}

void k_lock_enter(kLock* self)
{
	kint i;
	for (i = 0; !k_lock_try(self); i++)
		k_yield(i);
}

void k_lock_leave(kLock* self)
{
	KSAFE_BARRIER;
	*(volatile kint*)self = 0;
}
#endif


//////////////////////////////////////////////////////////////////////////
// yield, from BOOST yield

//
//  yield_k.hpp
//
//  Copyright (c) 2008 Peter Dimov
//
//  void yield( unsigned k );
//
//  Typical use:
//
//  for( unsigned k = 0; !try_lock(); ++k ) yield( k );
//
//  Distributed under the Boost Software License, Version 1.0.
//  See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt
//

void k_yield(kint step)
{
	if (step < 4)
	{
	}
#ifdef KSAFE_PAUSE
	else if (step < 16)
	{
		KSAFE_PAUSE;
	}
#endif
#if _SB_PTHREAD_
	else if (step < 32 || (step & 1))
	{
		sched_yield();
	}
	else
	{
#if 0
		k_msleep(1);
#else
		struct timespec ts;
		ts.tv_sec = 0;
		ts.tv_nsec = 1000;
		nanosleep(&ts, NULL);
#endif
	}
#else
	else if (step < 32)
	{
		k_sleep(0);
	}
	else
	{
		k_sleep(1);
	}
#endif
}
